﻿// Author: AustralTek 
// Create date: 2010/05/04
// http://www.australtek.com
// Copyright: 2009 - 2010

(function () {
    function _CalendarPicker(obj, options) {
        /*--------------------------*/
        /*----Private properties----*/
        /*--------------------------*/
        var containerAux;
        var container;
        var calendar;
        var datePicker;
        var monthSelect;
        var yearSelect;
        var privateParameters;

        /* Sets and Overrides certains properties.*/
        function _initialize(obj, options) {
            try {
                containerAux = obj;
                container = null;
                calendar = null;
                datePicker = null;
                monthSelect = null;
                yearSelect = null;

                privateParameters = new PrivateParameters(options);

                //Autostart
                var autoDate = getItem('date');

                privateParameters.Date = ((autoDate) && (autoDate != 'null')) ? new Date(getItem('date')) : ((privateParameters.Date) ? new Date(new Date(privateParameters.Date).toDateString()) : new Date(new Date().toDateString()));
                privateParameters.PreviousSelectedYear =
                privateParameters.SelectedYear = privateParameters.Date.getFullYear();
                privateParameters.PreviousSelectedMonth =
                privateParameters.SelectedMonth = privateParameters.Date.getMonth();
                privateParameters.PreviousSelectedDay = privateParameters.Date.getDate();
                var tempDate = new Date();
                privateParameters.CurrentYear = tempDate.getFullYear();
                privateParameters.CurrentMonth = tempDate.getMonth();
                privateParameters.CurrentDay = tempDate.getDate();

                privateParameters.CalendarParameters = privateParameters.CalendarParameters || new Object();
                privateParameters.CalendarParameters.Active = false;
                privateParameters.CalendarParameters.CalendarZIndex = 200;
                privateParameters.CalendarParameters.DaysCountPerMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
                privateParameters.CalendarParameters.Format = 'mm/dd/yyyy';
                privateParameters.CalendarParameters.DisplayTimeOutID = null;
                privateParameters.CalendarParameters.DisplayTimeOut = privateParameters.CalendarParameters.DisplayTimeOut || 10 * 1000;
                privateParameters.CalendarParameters.DayChars = privateParameters.CalendarParameters.DayChars || 1; // number of characters in day names abbreviation
                privateParameters.CalendarParameters.DayNames = privateParameters.CalendarParameters.DayNames || ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
                privateParameters.CalendarParameters.MonthNames = privateParameters.CalendarParameters.MonthNames || ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
                privateParameters.CalendarParameters.StartDay = privateParameters.CalendarParameters.StartDay || 7; // 1 = week starts on Monday, 7 = week starts on Sunday
                privateParameters.CalendarParameters.YearOrder = privateParameters.CalendarParameters.YearOrder || 1; // 1=asc , -1=desc
                privateParameters.CalendarParameters.YearRange = privateParameters.CalendarParameters.YearRange || 11;
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _redraw() {
            try {
                container = document.createElement('div');
                container.className = 'calendarPickersContainers';
                containerAux.appendChild(container);

                datePicker = document.createElement('input');
                datePicker.className = 'inputscalendarPickers';
                container.appendChild(datePicker);

                datePicker.value = _formatValue(privateParameters.Date.getFullYear(), privateParameters.Date.getMonth() + 1, privateParameters.Date.getDate());

                addEventHandler(datePicker, 'onclick', _datePickerClick);
                addEventHandler(datePicker, 'onkeypress', _datePickerKeypress);
                addEventHandler(datePicker, 'onmouseout', _datePickerMouseout);

                setTimeout(privateParameters.Events.onComplete, 1);
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        /*-----------------------------------------------------------------------*/
        /*-----------------------------------------------------------------------*/
        /*-----------------------------------------------------------------------*/
        try {
            /* Sets properties.*/
            _initialize(obj, options);
            _redraw();
        }
        catch (Error) { privateParameters.Events.onError(Error); }
        /*-----------------------------------------------------------------------*/
        /*-----------------------------------------------------------------------*/
        /*-----------------------------------------------------------------------*/

        /*-----------------------*/
        /*----Private methods----*/
        /*-----------------------*/
        /* Formats the returning date value according to the selected format.*/
        function _formatValue(year, month, day) {
            var dateStr = null;
            try {
                /* Checks the length of day.*/
                if (day < 10) day = '0' + day;
                if (month < 10) month = '0' + month;

                /* Checks the format & replaces parts.*/
                dateStr = privateParameters.CalendarParameters.Format.replace(/dd/i, day).replace(/mm/i, month).replace(/yyyy/i, year);
                //                privateParameters.SelectedMonth = privateParameters.PreviousSelectedMonth = '' + (month - 1) + '';
                //                privateParameters.SelectedYear = privateParameters.PreviousSelectedYear = year;
                //                privateParameters.PreviousSelectedDay = day;
            }
            catch (Error) { privateParameters.Events.onError(Error); }
            return dateStr;
        }

        /* Builds the calendar.*/
        function _buildCalendar() {
            try {
                datePicker.className = 'inputscalendarPickersFocus';
                privateParameters.CalendarParameters.DisplayTimeOutID = setTimeout(_hideCalendarTimeOut, privateParameters.CalendarParameters.DisplayTimeOut);

                /* Builds the outer container.*/
                var calendarContainer = document.createElement('div');
                calendarContainer.className = 'dpCalendarContainers';
                calendarContainer.style.zIndex = privateParameters.CalendarParameters.CalendarZIndex;
                container.appendChild(calendarContainer);

                addEventHandler(calendarContainer, 'onmouseover', _calendarContainerMouseover);
                addEventHandler(calendarContainer, 'onmouseout', _calendarContainerMouseout);
                //                $(container).addEvent('mouseleave',_calendarContainerMouseout);

                /* Builds the calendar.*/
                calendar = document.createElement('div');
                calendar.style.zIndex = privateParameters.CalendarParameters.CalendarZIndex;
                calendar.className = 'dpCal';
                calendarContainer.appendChild(calendar);

                /* Sets the count of days of February.*/
                privateParameters.CalendarParameters.DaysCountPerMonth[1] = (privateParameters.SelectedYear % 4 == 0) ? 29 : 28

                /* Creates the month select box.*/
                monthSelect = document.createElement('select');
                monthSelect.className = 'monthSelect';
                for (var iMonth = 0; iMonth < privateParameters.CalendarParameters.MonthNames.length; iMonth++) {
                    var month = document.createElement('option');
                    month.innerHTML = privateParameters.CalendarParameters.MonthNames[iMonth];
                    month.value = iMonth;
                    monthSelect.appendChild(month);
                }
                monthSelect[privateParameters.SelectedMonth].selected = true;

                /* Creates the year select box.*/
                yearSelect = document.createElement('select');
                yearSelect.className = 'yearSelect';

                for (var iYear = 0; iYear < privateParameters.CalendarParameters.YearRange; iYear++) {
                    var year = document.createElement('option');
                    year.innerHTML =
                    year.value = privateParameters.CurrentYear - ((parseInt(privateParameters.CalendarParameters.YearRange / 2)) * privateParameters.CalendarParameters.YearOrder) + (iYear * privateParameters.CalendarParameters.YearOrder);
                    yearSelect.appendChild(year);
                    if (parseInt(year.value) == privateParameters.SelectedYear)
                        yearSelect[yearSelect.length - 1].selected = true;
                }

                /* Draws calendar.*/
                var calTable = document.createElement('table');
                var calTableThead = document.createElement('thead');
                var calSelRow = document.createElement('tr');
                var calSelCell = document.createElement('th');
                calSelCell.colSpan = 7;
                calSelCell.appendChild(monthSelect);
                calSelCell.appendChild(yearSelect);
                calSelRow.appendChild(calSelCell);
                calTableThead.appendChild(calSelRow);
                calTable.appendChild(calTableThead);
                var calTableTbody = document.createElement('tbody');

                /* Creates days names.*/
                var calDayNameRow = document.createElement('tr');
                for (var iDayName = 0; iDayName < privateParameters.CalendarParameters.DayNames.length; iDayName++) {
                    var calDayNameCell = document.createElement('td');
                    calDayNameCell.innerHTML = privateParameters.CalendarParameters.DayNames[(privateParameters.CalendarParameters.StartDay + iDayName) % 7].substr(0, privateParameters.CalendarParameters.DayChars);
                    calDayNameRow.appendChild(calDayNameCell);
                }
                calTableTbody.appendChild(calDayNameRow);
                calTable.appendChild(calTableTbody);
                calendar.appendChild(calTable);

                /* Sets the day to first of the month.*/
                var tempDate = new Date(new Date().setFullYear(privateParameters.SelectedYear, privateParameters.SelectedMonth, 1));
                var firstDay = (1 - (7 + tempDate.getDay() - privateParameters.CalendarParameters.StartDay) % 7);

                /* Creates the days cells.*/
                while (firstDay <= privateParameters.CalendarParameters.DaysCountPerMonth[privateParameters.SelectedMonth]) {
                    var calDayRow = document.createElement('tr');
                    for (var iDay = 0; iDay < 7; iDay++) {
                        var calDayCell = document.createElement('td');
                        if ((firstDay <= privateParameters.CalendarParameters.DaysCountPerMonth[privateParameters.SelectedMonth]) && (firstDay > 0)) {
                            calDayCell.className =
		                    calDayCell.originalCssClass = 'dpCalDay';
                            calDayCell.altCssClass = 'dpRoll';
                            calDayCell.axis = privateParameters.SelectedYear + '|' + (privateParameters.SelectedMonth + 1) + '|' + firstDay;
                            calDayCell.innerHTML = firstDay;

                            addEventHandler(calDayCell, 'onmouseover', _calDayCellMouseover);
                            addEventHandler(calDayCell, 'onmouseout', _calDayCellMouseout);
                            addEventHandler(calDayCell, 'onclick', _calDayCellClick);
                        }
                        else {
                            calDayCell.className = 'dpEmpty';
                            calDayCell.innerHTML = '&nbsp;';
                        }
                        /* Selects today.*/
                        if ((firstDay == privateParameters.CurrentDay) && (privateParameters.SelectedMonth == privateParameters.CurrentMonth) && (privateParameters.SelectedYear == privateParameters.CurrentYear))
                            calDayCell.className =
		                    calDayCell.originalCssClass = 'dpToday';
                        /* Selects the previous day.*/
                        if ((firstDay == privateParameters.PreviousSelectedDay) && (privateParameters.SelectedMonth == privateParameters.PreviousSelectedMonth) && (privateParameters.SelectedYear == privateParameters.PreviousSelectedYear))
                            calDayCell.className =
		                    calDayCell.originalCssClass = 'dpSelected';

                        calDayRow.appendChild(calDayCell);
                        firstDay++
                    }
                    calTableTbody.appendChild(calDayRow);
                }

                /* Sest the onchange event for the month & year select boxes.*/
                addEventHandler(monthSelect, 'onfocus', _monthSelectFocus);
                addEventHandler(yearSelect, 'onfocus', _yearSelectFocus);
                addEventHandler(monthSelect, 'onblur', _monthSelectBlur);
                addEventHandler(yearSelect, 'onblur', _yearSelectBlur);
                addEventHandler(monthSelect, 'onchange', _monthSelectChange);
                addEventHandler(yearSelect, 'onchange', _yearSelectChange);
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        /* Hides the calendar from the page.*/
        function _hideCalendar() {
            try {
                if (!privateParameters.CalendarParameters.Active) {
                    privateParameters.SelectedMonth = privateParameters.PreviousSelectedMonth;
                    privateParameters.SelectedYear = privateParameters.PreviousSelectedYear;
                    if (privateParameters.CalendarParameters.DisplayTimeOutID) clearTimeout(privateParameters.CalendarParameters.DisplayTimeOutID);
                    datePicker.className = 'inputscalendarPickers';
                    removeEventHandler(calendar.parentNode, 'onmouseover', _calendarContainerMouseover);
                    removeEventHandler(calendar.parentNode, 'onmouseout', _calendarContainerMouseout);
                    container.removeChild(calendar.parentNode);
                    calendar = null;
                }
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _hideCalendarTimeOut() {
            try {
                privateParameters.SelectedMonth = privateParameters.PreviousSelectedMonth;
                privateParameters.SelectedYear = privateParameters.PreviousSelectedYear;
                _hideCalendar();
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _refreshCalendar() {
            try {
                privateParameters.CalendarParameters.Active = false;
                _hideCalendar();
                privateParameters.SelectedMonth = parseInt(monthSelect.value);
                privateParameters.SelectedYear = parseInt(yearSelect.value);
                _buildCalendar();
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _moveNext() {
            try {
                _changeDate(new Date(privateParameters.Date.getTime() + 86400000));
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        };
        function _movePrevious() {
            try {
                _changeDate(new Date(privateParameters.Date.getTime() - 86400000));
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        };

        /* Sets "privateParameters.Date" and input's value.*/
        function _setValue(newDate) {
            try {
                privateParameters.Date = newDate;
                privateParameters.PreviousSelectedDay =
                privateParameters.SelectedDay = newDate.getDate();
                privateParameters.PreviousSelectedMonth =
                privateParameters.SelectedMonth = newDate.getMonth();
                privateParameters.PreviousSelectedYear =
                privateParameters.SelectedYear = newDate.getFullYear();
                datePicker.value = _formatValue(privateParameters.SelectedYear, privateParameters.SelectedMonth + 1, privateParameters.SelectedDay);
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        /* Changes "privateParameters.Date" and input's value and trigger the "onChangeDate" event.*/
        function _changeDate(newDate) {
            try {
                /* Check if date really changed.*/
                if (privateParameters.Date.getTime() != newDate.getTime()) {
                    _setValue(newDate);
                    privateParameters.Events.onChange();
                }
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _getStringDate(options) {
            var ret = null;
            try {
                options = options || { DBEngine: 'SQLServer', paramsWishList: null }; //DBEngine = SQL Server by default.
                options.DBEngine = options.DBEngine || 'SQLServer';

                var DBType = 4; //Type = DATETIME (SQLServer type by default)

                switch (options.DBEngine.toUpperCase()) {
                    case 'SQLSERVER': break;
                    case 'ORACLE': DBType = 106; break; //Type = DATE
                    default: throw Error;
                };

                ret = new QueryParameters({ DBEngine: options.DBEngine });

                ret.Add('Date', DBType, _formatValue(privateParameters.Date.getFullYear(), privateParameters.Date.getMonth() + 1, privateParameters.Date.getDate()));
            }
            catch (Error) { privateParameters.Events.onError(Error); }
            return ret;
        }

        function _resetCssClass(e) {
            try {
                var target = e.target || e.srcElement;
                target.className = target.originalCssClass;
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _changeCssClass(e) {
            try {
                var target = e.target || e.srcElement;
                target.className = target.altCssClass;
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        /*------------------*/
        /*------Events------*/
        /*------------------*/

        function _datePickerClick() {
            _buildCalendar();
        }

        function _datePickerKeypress(e) {
            try {
                try {
                    e.preventDefault(e);
                }
                catch (Error) {
                    e.returnValue = false;
                }
            }
            catch (Error) {
                privateParameters.Events.onError(Error);
                return false;
            }
        }

        function _datePickerMouseout(e) {
            try {
                var elementDestiny = e.toElement || e.relatedTarget;
                if ((calendar) && (calendar.parentNode) && (_hasChild(calendar.parentNode, elementDestiny) == false) && (elementDestiny != calendar.parentNode))
                    _hideCalendar();
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _calendarContainerMouseover() {
            try {
                clearTimeout(privateParameters.CalendarParameters.DisplayTimeOutID);
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _calendarContainerMouseout(e) {
            try {
                var elementDestiny = e.toElement || e.relatedTarget;
                if (_hasChild(calendar.parentNode, elementDestiny) == false)
                    _hideCalendar();
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _hasChild(parent, childToFind) {
            try {
                if (parent.children.length > 0) {
                    for (var iChild = 0; iChild < parent.children.length; iChild++) {
                        if (parent.children[iChild] == childToFind)
                            return true;
                        else
                            if (_hasChild(parent.children[iChild], childToFind) == true)
                                return true;
                    }
                }
            }
            catch (Error) { privateParameters.Events.onError(Error); }
            return false;
        }

        function _monthSelectFocus() {
            try {
                privateParameters.CalendarParameters.Active = true;
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _monthSelectBlur() {
            try {
                privateParameters.CalendarParameters.Active = false;
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _monthSelectChange() {
            try {
                _refreshCalendar();
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _yearSelectFocus() {
            try {
                privateParameters.CalendarParameters.Active = true;
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _yearSelectBlur() {
            try {
                privateParameters.CalendarParameters.Active = false;
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _yearSelectChange() {
            try {
                _refreshCalendar();
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _calDayCellClick(e) {
            try {
                var target = e.srcElement || e.target;
                var dayPickedValues = target.axis.split('|');
                _changeDate(new Date(dayPickedValues[1] + '/' + dayPickedValues[2] + '/' + dayPickedValues[0]));
                _hideCalendar();
            }
            catch (Error) { privateParameters.Events.onError(Error); }
        }

        function _calDayCellMouseover(e) {
            _changeCssClass(e);
        }

        function _calDayCellMouseout(e) {
            _resetCssClass(e);
        }

        /*----------------*/
        /*-----Public-----*/
        /*----------------*/

        /*----------------------*/
        /*--------Methods-------*/
        /*----------------------*/
        this.MovePrevious = function () {
            _movePrevious();
        };
        this.MoveNext = function () {
            _moveNext();
        };
        this.GetResults = function (options) {
            return _getStringDate(options);
        };
        this.SetValue = function (newDate) {
            _setValue(newDate);
        };
    }

    window.CalendarPicker = function (obj, instanceOptions) { return new _CalendarPicker(obj, instanceOptions); };
})();